<?php
namespace bee;

define("DAO_POST_NONE", 0);
define("DAO_POST_SELECT", 1);
//define("DAO_POST_INSERT_ID", 2);
//define("DAO_POST_ALL", 3);
define("DAO_PK_AUTO", 256);

abstract class DAO extends object
{
  /**
   *
   * @var db
   */
  protected $__conn;
  /**
   *
   * @var \Exception
   */
  public    $__exception;
  protected $__table;
  protected $__insert_array;
  protected $__update_array;
  protected $__param_types;
  protected $__PKAutoNumber = true;
  protected $__PKname = "id";
  protected  $__SQL = array();

  //private $DAO_props = array("_class", "__exception", "__conn", "__table", "cls_props", "__insert_array", "__update_array", "__param_types", "__withEvents", "__objectID", "__PKAutoNumber", "__PKname", "__SQL");

  private $DAO_props = array("__withEvents", "__objectID", "emptyValue", "__conn", "__exception", "__table", "__insert_array", "__update_array", "__param_types",  "__PKAutoNumber", "__PKname", "__SQL");
  public function SELECT($id = NULL)
  {	$pkName = $this->__PKname;
    if($id === NULL)
  	{	$id = $this->$pkName;
  	}
  	$c = $this->__conn;
  	$sqt = "SELECT * FROM " . $c->__NAME_OPEN . $this->__table . $c->__NAME_CLOSE . " WHERE " . $c->__NAME_OPEN . $pkName . $c->__NAME_CLOSE . " = :$pkName";
    $this->__SQL["SELECT"] = $sqt;
  	$stmt = $c->prepare($sqt);
  	$stmt->bindParam(":$pkName", $id);
  	$stmt->setFetchMode(\PDO::FETCH_INTO, $this);
  	if($stmt->execute())
  	{ if($row = $stmt->fetch(\PDO::FETCH_INTO ))
  	  {	return 1;
  	  }
  	}
    $where_refl = new \ReflectionClass(get_called_class());
  	$cls_props = $where_refl->getProperties();
  	foreach ($cls_props as $prop)
  	{ if(!in_array($prop->name, $this->DAO_props))
  	  {	$pn = $prop->name;
        $this->$pn = "";
  	  }
  	}
  	return 0;
  }

  public function DELETE()
  {	$pkName = $this->__PKname;
    $sqt = "DELETE FROM " . $this->__conn->__NAME_OPEN . $this->__table . $this->__conn->__NAME_CLOSE . " WHERE $pkName = :$pkName";
    $this->__SQL["DELETE"] = $sqt;
    $stmt = $this->__conn->prepare($sqt);
  	$stmt->bindParam(":$pkName", $this->$pkName, \PDO::PARAM_INT);
  	if($stmt->execute())
  	{	return 1;
  	}
  	return 0;
  }

	/**
	 * @return int
	 */
  public function INSERT($params = DAO_POST_SELECT)
  {	try
    { $c = $this->__conn;
  	  $sqt = "INSERT INTO " . $c->__NAME_OPEN . $this->__table . $this->__conn->__NAME_CLOSE . " (" . $c->__NAME_OPEN
  	 . implode($c->__NAME_CLOSE . ", " . $c->__NAME_OPEN, $this->__insert_array) . $c->__NAME_CLOSE . ") VALUES (:"
  	 . implode(", :", $this->__insert_array) . ")";
  	  $this->__SQL["INSERT"] = $sqt;
  	  $cfg = config::getInstance();
  		$stmt = $this->__conn->prepare($sqt);
  		foreach ($this->__insert_array as $insert_field)
  		{ if($insert_field != $this->__PKname)
  		  { if(is_string($this->$insert_field))
  		    {
  		    } else
  		    {}
  			  $stmt->bindParam(":" . $insert_field, $this->$insert_field); // doraditi bindanje po tipu
  		  }
  		}
  		/**
  		 * @todo problem kada pk nije autonumber
  		 */
  		if($stmt->execute())
  		{ if( ($params & DAO_POST_SELECT) == DAO_POST_SELECT)
  		  { if(($cfg->sql__DATABASE_TYPE & DB_ENGINE_MSSQL) == DB_ENGINE_MSSQL && false)
    		  { $stmt = $this->__conn->query("SELECT @@IDENTITY");
            $row = $stmt->fetch(\PDO::FETCH_NUM);
            $this->SELECT($row[0]);
          } else
          { $this->SELECT($this->__conn->lastInsertId());
          }
  		  }
  		  return 1;
  		}
  		return 0;
    } catch(\Exception $ex)
    { $this->__exception = $ex;
      return 0;
    }
  }

	public function UPDATE()
	{ $PKname = $this->__PKname;
	  $sqt = "UPDATE " . $this->__conn->__NAME_OPEN . $this->__table . $this->__conn->__NAME_CLOSE
	  . " SET " . implode(", ", $this->__update_array) . " WHERE $PKname = :$PKname ";
	  $stmt = $this->__conn->prepare($sqt);
		$this->__SQL["UPDATE"] = $sqt;
	  foreach ($this->__insert_array as $insert_field)
	  { /*
	    $tif = "__" . $insert_field . "";
        if(is_string($this->$insert_field))
        { $this->$tif = $this->$insert_field;
      	  // //$this->$tif = iconv("UTF-8", "Windows-1250", $this->$insert_field);
        } else
        { $this->$tif = $this->$insert_field;
        }
        */
        $stmt->bindParam(":" . $insert_field, $this->$insert_field);//, $this->param_types[$insert_field]); // doraditi bindanje po tipu
      }
      $stmt->bindParam(":$PKname", $this->$PKname, \PDO::PARAM_INT);

      if($stmt->execute())
      { return 1;
      }
      return 0;
	}

	public function __construct($pk = 0, db $connection = NULL)
	{ if($connection)
	  { $this->__conn = $connection;
	  //echo("*****************" . print_r($this, true));
	  } else
	  { $this->__conn = db::getInstance();

	  }
	  $this->__withEvents = false;

	  if($pk)
	  {	$this->SELECT($pk);
	  }
      $this->__table = str_replace("\\", "_", get_called_class());

      $where_refl = new \ReflectionClass(get_called_class());
      $cls_props = $where_refl->getProperties();
      $this->__insert_array = array();
      $this->__update_array = array();
//die(print_r($this->__conn, true));

      foreach ($cls_props as $prop)
      {	if(!in_array($prop->name, $this->DAO_props) && ($prop->name != $this->__PKname || $this->__PKAutoNumber == false))
      	{ $this->__update_array[$prop->name] = $this->__conn->__NAME_OPEN . $prop->name . $this->__conn->__NAME_CLOSE . " = :" . $prop->name;// . $daoRow->prepareSQL($daoRow->{$prop->name}, true);
      	  $this->__insert_array[":" .$prop->name] = $prop->name;
      	}
      }
	}

	public function __get($name)
	{ $PKeyName = $this->__PKname;
	  $PKeyValue = $this->$PKeyName;
	  if($PKeyValue)
	  { return getAttribute($this->__table, $PKeyValue, $name);
	  }
	}

	public function __set($name, $value)
	{ $PKeyName = $this->__PKname;
	  $PKeyValue = $this->$PKeyName;
	  if($PKeyValue)
	  { setAattribute($this->__table, $PKeyValue, $name, $value);
	  }
	}

	public function getSysTable()
	{	return $this->__table;
	}
	public function geSysTable()
	{	return $this->__table;

	}
	public function getConn()
	{	return $this->__conn;
	}

	public function fillFromArray($array = "", $arr_prefix = "", $empty2null = true)//default $_REQUEST
	{	if(!is_array($array))
		{	$array = $_REQUEST;
		}
		$refl = new \ReflectionClass(get_class($this));
		//print_r($refl);
		$class_props = $refl->getProperties();
		//print_r($class_props);
		foreach ($class_props as $prop)
		{	if(isset($array[$arr_prefix . $prop->name]) && !in_array($prop->name, $this->DAO_props))// && !is_null($array[$arr_prefix . $prop->name]))// bilo isset(...)
			{	$pn = $prop->name;
				$this->$pn = $array[$arr_prefix . $pn];
			}
		}
	}

	public function clear()
	{ $refl = new \ReflectionClass(get_class($this));
	  $class_props = $refl->getProperties();
	  foreach ($class_props as $prop)
	  { if(!in_array($prop->name, $this->DAO_props))
	    { $pn = $prop->name;
	      $this->$pn = null;
	    }
	  }
	}

  public function __wakeup()
  { //echo("..." . var_dump($this->__conn));

    if($this->__conn instanceof db && $this->__conn->getConnName())
    { $db = db::getInstance();
      $this->__conn = $db->getSecConnection($this->__conn->getConnName());

    }  else
    { $this->__conn = db::getInstance();
    }
  }

  public function getSQL($operation)
  { return $this->__SQL[$operation];
  }

}
